﻿using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Windows.Interactivity;
using Odyssey.Utils;
using System.Linq;
using System.Diagnostics;

namespace Odyssey.Behaviors
{
    /// <summary>
    /// When the enter button is pressed in a textbox which is an element of an item in a ItemsControl, the next item of the ItemsControl gets the focus.
    /// </summary>
    public class ItemsEnterNavigationBehavior : Behavior<ItemsControl>
    {
        /// <summary>
        /// Gets or sets whether to navigate cyclic or only from top to bottom.
        /// </summary>
        public bool Cyclic { get; set; }

        protected override void OnAttached()
        {
            AssociatedObject.KeyUp += new KeyEventHandler(OnKeyUp);
            base.OnAttached();
        }

        protected override void OnDetaching()
        {
            AssociatedObject.KeyUp -= OnKeyUp;
            base.OnDetaching();
        }

        void OnKeyUp(object sender, KeyEventArgs e)
        {
            if (e.Key == Key.Enter)
            {
                TextBox tb = FocusManager.GetFocusedElement() as TextBox;
                if (tb != null && !tb.AcceptsReturn)
                {
                    tb = FocusNext(e) as TextBox;
                    ScrollToCursor(tb);
                }
                else
                {
                    //TextBox tb = FocusManager.GetFocusedElement() as TextBox;
                    ScrollToCursor(tb);
                }

            }
        }

        private void ScrollToCursor(TextBox tb)
        {
            if (tb != null && (tb.TextWrapping == TextWrapping.Wrap || tb.AcceptsReturn))
            {
                if (tb.SelectionStart == tb.Text.Length)
                {
                    ScrollViewer sv = tb.GetVisualAncestors().OfType<ScrollViewer>().FirstOrDefault();
                    if (sv != null)
                    {
                        Rect? bounds = tb.GetBoundsRelativeTo(sv);
                        if (bounds != null)
                        {
                            Rect rect = bounds.Value;
                            sv.ScrollToVerticalOffset(sv.VerticalOffset + rect.Bottom - sv.ActualHeight / 2);
                        }

                    }
                }
            }
        }

        private Control FocusNext(KeyEventArgs e)
        {
            FrameworkElement src = e.OriginalSource as FrameworkElement;
            Panel itemsHost = AssociatedObject.GetVisualDescendants().OfType<Panel>().FirstOrDefault(p => p.IsItemsHost);
            if (itemsHost != null)
            {
                var items = itemsHost.GetVisualChildren().OfType<FrameworkElement>().ToArray();
                foreach (var item in items)
                {
                    if (src.GetVisualAncestors().Any(a => a == item))
                    {
                        int index = AssociatedObject.ItemContainerGenerator.IndexFromContainer(item);

                        if (index < AssociatedObject.Items.Count - 1) index++; else index = Cyclic ? 0 : -1;
                        if (index >= 0)
                        {
                            var container = AssociatedObject.ItemContainerGenerator.ContainerFromIndex(index) as FrameworkElement;
                            if (container != null)
                            {
                                Control next = container.GetVisualDescendantsAndSelf().OfType<Control>().FirstOrDefault();
                                if (next == null) next = container.GetVisualDescendantsAndSelf().OfType<PasswordBox>().FirstOrDefault();
                                ScrollViewer sv = container.GetVisualAncestors().OfType<ScrollViewer>().FirstOrDefault();
                                if (sv != null)
                                {
                                    Rect? bounds = container.GetBoundsRelativeTo(sv);
                                    if (bounds != null)
                                    {
                                        Rect rect = bounds.Value;
                                        sv.ScrollToVerticalOffset(sv.VerticalOffset + rect.Top - rect.Height);
                                    }
                                }
                                if (next != null)
                                {
                                    next.Focus();
                                    return next;
                                }
                            }
                        }
                    }
                }
            }
            return null;
        }

    }
}
